/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package dnbW.entityW;

import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.ListIterator;
import java.util.Set;

/**
 * Encapsulates an iterator that iterates through the ER graph (Iterator pattern)
 * @author truongbaquan
 */
public class EntityIterator implements Iterator {
    public static enum Direction {Down, Up};

    private LinkedList<IEntity> list = new LinkedList<IEntity>();
    private ListIterator curIterator;
    private Direction direction;
    private Set<Relationship> relationshipSet = new HashSet<Relationship>();
    private LinkedList<IEntity> sourceList = new LinkedList<IEntity>();

    private IEntity curSource;

    public IEntity getCurSource() {
        return curSource;
    }

    public EntityIterator(IEntity origin, Direction direction) {
        this.sourceList.add(origin);
        this.direction = direction;
        this.curIterator = this.list.listIterator();
    }

    private LinkedList<IEntity> getEntityListByDirection(IEntity source) {
        LinkedList<IEntity> returnResult = new LinkedList<IEntity>();
        for (IEntity other : source.getRelatedEntities()) {
            Relationship relationship = source.getRelationship(other);
            if (!this.relationshipSet.contains(relationship)) {
                this.relationshipSet.add(relationship);
                if (source.getCardinality(relationship) == Cardinality.one) {
                    if (other.getCardinality(relationship) == Cardinality.one) { // 1-1
                        returnResult.add(other);
                    }
                    else if (other.getCardinality(relationship) == Cardinality.many) { // 1-n
                        if (this.direction == Direction.Down) {
                            returnResult.add(other);
                        }
                    }
                }
                else if (source.getCardinality(relationship) == Cardinality.many) {
                    if (other.getCardinality(relationship) == Cardinality.one) { // n-1
                        if (this.direction == Direction.Up) {
                            returnResult.add(other);
                        }
                    }
                    else if (other.getCardinality(relationship) == Cardinality.many) { // m-n
                        returnResult.add(other);
                    }
                }
            }
        }
        return returnResult;
    }

    @Override
    public boolean hasNext() {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    @Override
    public Object next() {
        if (this.curIterator.hasNext()) {
            return this.curIterator.next();
        }
        else {
            Collection<IEntity> newList = refillList();
            sourceList.addAll(newList);
            if (!this.list.isEmpty()) {
                this.curIterator = this.list.listIterator();
                return this.curIterator.next();
            }
            else { // no more
                return null;
            }
        }
    }

    @Override
    public void remove() {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    private Collection<IEntity> refillList() {
        this.list.clear();
        while (this.list.isEmpty() && !this.sourceList.isEmpty()) {
            this.curSource = this.sourceList.removeFirst();
            this.list.addAll(this.getEntityListByDirection(curSource));
        }
        return list;
    }

}
